001/* 002 * (C) Copyright 2006-2008 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 * bstefanescu 016 * 017 * $Id$ 018 */ 019 020package org.nuxeo.ecm.webengine.model.impl; 021 022import java.io.File; 023import java.io.IOException; 024import java.net.URISyntaxException; 025import java.net.URL; 026import java.text.ParseException; 027import java.util.Set; 028import java.util.concurrent.ConcurrentHashMap; 029import java.util.concurrent.ConcurrentMap; 030 031import org.nuxeo.ecm.webengine.WebEngine; 032import org.nuxeo.ecm.webengine.WebException; 033import org.nuxeo.ecm.webengine.loader.ClassProxy; 034import org.nuxeo.ecm.webengine.model.Module; 035import org.nuxeo.ecm.webengine.model.Resource; 036import org.nuxeo.ecm.webengine.model.ResourceType; 037import org.nuxeo.ecm.webengine.model.TemplateNotFoundException; 038import org.nuxeo.ecm.webengine.model.TypeVisibility; 039import org.nuxeo.ecm.webengine.scripting.ScriptFile; 040import org.nuxeo.ecm.webengine.security.Guard; 041import org.nuxeo.ecm.webengine.security.PermissionService; 042import org.nuxeo.runtime.annotations.AnnotationManager; 043 044/** 045 * @author <a href="mailto:bs@nuxeo.com">Bogdan Stefanescu</a> 046 */ 047public abstract class AbstractResourceType implements ResourceType { 048 049 protected final ModuleImpl owner; 050 051 protected final String name; 052 053 protected int visibility = TypeVisibility.DEFAULT; 054 055 protected AbstractResourceType superType; 056 057 protected volatile ClassProxy clazz; 058 059 protected volatile Guard guard = Guard.DEFAULT; 060 061 protected volatile Set<String> facets; 062 063 protected volatile ConcurrentMap<String, ScriptFile> templateCache; 064 065 protected AbstractResourceType(WebEngine engine, ModuleImpl module, AbstractResourceType superType, String name, 066 ClassProxy clazz, int visibility) { 067 templateCache = new ConcurrentHashMap<String, ScriptFile>(); 068 owner = module; 069 this.superType = superType; 070 this.name = name; 071 this.clazz = clazz; 072 this.visibility = visibility; 073 AnnotationManager mgr = engine.getAnnotationManager(); 074 loadAnnotations(mgr); 075 } 076 077 public int getVisibility() { 078 return visibility; 079 } 080 081 protected abstract void loadAnnotations(AnnotationManager annoMgr); 082 083 public ResourceType getSuperType() { 084 return superType; 085 } 086 087 public Module getOwnerModule() { 088 return owner; 089 } 090 091 public Guard getGuard() { 092 return guard; 093 } 094 095 public Set<String> getFacets() { 096 return facets; 097 } 098 099 public boolean hasFacet(String facet) { 100 return facets != null && facets.contains(facet); 101 } 102 103 public String getName() { 104 return name; 105 } 106 107 @SuppressWarnings("unchecked") 108 public Class<Resource> getResourceClass() { 109 return (Class<Resource>) clazz.get(); 110 } 111 112 @SuppressWarnings("unchecked") 113 public <T extends Resource> T newInstance() { 114 try { 115 return (T) clazz.get().newInstance(); 116 } catch (ReflectiveOperationException e) { 117 throw WebException.wrap("Failed to instantiate web object: " + clazz, e); 118 } 119 } 120 121 public boolean isEnabled(Resource ctx) { 122 return guard.check(ctx); 123 } 124 125 public boolean isDerivedFrom(String type) { 126 if (type.equals(name)) { 127 return true; 128 } 129 if (superType != null) { 130 return superType.isDerivedFrom(type); 131 } 132 return false; 133 } 134 135 public void flushCache() { 136 templateCache = new ConcurrentHashMap<String, ScriptFile>(); 137 } 138 139 protected void loadGuardFromAnnoation(Class<?> c) { 140 org.nuxeo.ecm.webengine.model.Guard ag = c.getAnnotation(org.nuxeo.ecm.webengine.model.Guard.class); 141 if (ag != null) { 142 String g = ag.value(); 143 if (g != null && g.length() > 0) { 144 try { 145 guard = PermissionService.parse(g); 146 } catch (ParseException e) { 147 throw WebException.wrap("Failed to parse guard: " + g + " on WebObject " + c.getName(), e); 148 } 149 } else { 150 Class<?> gc = ag.type(); 151 if (gc != null) { 152 try { 153 guard = (Guard) gc.newInstance(); 154 } catch (ReflectiveOperationException e) { 155 throw WebException.wrap("Failed to instantiate guard handler: " + gc.getName() 156 + " on WebObject " + c.getName(), e); 157 } 158 } 159 } 160 } 161 } 162 163 @Override 164 public String toString() { 165 return name + " extends " + superType + " [" + getResourceClass().getName() + "]"; 166 } 167 168 public ScriptFile getView(Module module, String name) { 169 ScriptFile file = findView(module, name); 170 if (file == null) { 171 throw new TemplateNotFoundException(this, name); 172 } 173 return file; 174 } 175 176 public ScriptFile findView(Module module, String name) { 177 ScriptFile file = templateCache.get(name); 178 if (file != null) { 179 return file; 180 } 181 file = findSkinTemplate(module, name); 182 if (file == null) { 183 file = findTypeTemplate(module, name); 184 } 185 if (file == null) { 186 AbstractResourceType t = (AbstractResourceType) getSuperType(); 187 if (t != null) { 188 file = t.findView(module, name); 189 } 190 } 191 if (file != null) { 192 templateCache.put(name, file); 193 } 194 return file; 195 } 196 197 protected ScriptFile findSkinTemplate(Module module, String name) { 198 return module.getFile(new StringBuilder().append("views").append(File.separatorChar).append(this.name).append( 199 File.separatorChar).append(name).toString()); 200 } 201 202 protected ScriptFile findTypeTemplate(Module module, String name) { 203 String path = resolveResourcePath(clazz.getClassName(), name); 204 URL url = clazz.get().getResource(path); 205 if (url != null) { 206 if (!"file".equals(url.getProtocol())) { 207 // TODO ScriptFile is not supporting URLs .. must refactor ScriptFile 208 return null; 209 } 210 try { 211 return new ScriptFile(new File(url.toURI())); 212 } catch (IOException | URISyntaxException e) { 213 throw WebException.wrap("Failed to convert URL to URI: " + url, e); 214 } 215 } 216 return null; 217 } 218 219 protected String resolveResourcePath(String className, String fileName) { 220 // compute resource path for resource class name 221 String path = className; 222 int p = path.lastIndexOf('.'); 223 if (p > -1) { 224 path = path.substring(0, p); 225 path = path.replace('.', '/'); 226 return new StringBuilder().append('/').append(path).append('/').append(fileName).toString(); 227 } 228 return new StringBuilder().append('/').append(fileName).toString(); 229 } 230 231}