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