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