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.net.URI; 023import java.net.URISyntaxException; 024import java.security.Principal; 025import java.text.ParseException; 026import java.util.List; 027import java.util.Set; 028 029import javax.ws.rs.core.Response; 030 031import org.nuxeo.common.utils.URIUtils; 032import org.nuxeo.ecm.core.api.CoreSession; 033import org.nuxeo.ecm.webengine.WebException; 034import org.nuxeo.ecm.webengine.model.AdapterResource; 035import org.nuxeo.ecm.webengine.model.LinkDescriptor; 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.Template; 040import org.nuxeo.ecm.webengine.model.View; 041import org.nuxeo.ecm.webengine.model.WebContext; 042import org.nuxeo.ecm.webengine.model.exceptions.WebSecurityException; 043import org.nuxeo.ecm.webengine.security.PermissionService; 044 045/** 046 * @author <a href="mailto:bs@nuxeo.com">Bogdan Stefanescu</a> 047 */ 048// DO NOT MODIFY class declaration! Cannot use WebResourceType<?> since groovy 049// doesn't supports wildcards for now 050@SuppressWarnings("unchecked") 051public abstract class AbstractResource<T extends ResourceType> implements Resource { 052 053 protected WebContext ctx; 054 055 protected AbstractResource<?> next; 056 057 protected AbstractResource<?> prev; 058 059 protected String path; 060 061 protected T type; 062 063 public Resource initialize(WebContext ctx, ResourceType type, Object... args) { 064 this.ctx = ctx; 065 this.type = (T) type; 066 path = ctx.getUriInfo().getMatchedURIs().get(0); 067 // quote path component to replace special characters (except slash and 068 // @ chars) 069 path = URIUtils.quoteURIPathComponent(path, false, false); 070 // avoid paths ending in / -> this will mess-up URLs in FTL files. 071 if (path.endsWith("/")) { 072 path = path.substring(0, path.length() - 1); 073 } 074 // resteasy doesn't return correct paths - that should be relative as 075 // is JAX-RS specs on resteasy paths begin with a / 076 StringBuilder buf = new StringBuilder(64).append(ctx.getBasePath()); 077 if (!path.startsWith("/")) { 078 buf.append('/'); 079 } 080 path = buf.append(path).toString(); 081 if (!this.type.getGuard().check(this)) { 082 throw new WebSecurityException("Failed to initialize object: " + path 083 + ". Object is not accessible in the current context", path); 084 } 085 initialize(args); 086 return this; 087 } 088 089 protected void initialize(Object... args) { 090 // do nothing 091 } 092 093 public boolean isAdapter() { 094 return type.getClass() == AdapterTypeImpl.class; 095 } 096 097 public boolean isRoot() { 098 return this == ctx.getRoot(); 099 } 100 101 public void setRoot(boolean isRoot) { 102 AbstractWebContext ctx = (AbstractWebContext) this.ctx; 103 if (isRoot) { 104 ctx.root = this; 105 } else { 106 if (ctx.root == this) { 107 ctx.root = null; 108 } 109 } 110 } 111 112 public boolean isInstanceOf(String type) { 113 return this.type.isDerivedFrom(type); 114 } 115 116 public Response redirect(String uri) { 117 try { 118 if (!uri.contains("://")) { 119 // not an absolute URI 120 if (uri.startsWith("/")) { 121 uri = ctx.getServerURL().append(uri).toString(); 122 } else { 123 uri = ctx.getServerURL().append('/').append(uri).toString(); 124 } 125 } 126 return Response.seeOther(new URI(uri)).build(); 127 } catch (URISyntaxException e) { 128 throw WebException.wrap(e); 129 } 130 } 131 132 public AdapterResource getActiveAdapter() { 133 return next != null && next.isAdapter() ? (AdapterResource) next : null; 134 } 135 136 public void dispose() { 137 ctx = null; 138 type = null; 139 path = null; 140 } 141 142 public Set<String> getFacets() { 143 return type.getFacets(); 144 } 145 146 public boolean hasFacet(String facet) { 147 return type.hasFacet(facet); 148 } 149 150 public T getType() { 151 return type; 152 } 153 154 public WebContext getContext() { 155 return ctx; 156 } 157 158 public Module getModule() { 159 return ctx.getModule(); 160 } 161 162 public Resource getNext() { 163 return next; 164 } 165 166 public void setNext(Resource next) { 167 this.next = (AbstractResource<?>) next; 168 } 169 170 public Resource getPrevious() { 171 return prev; 172 } 173 174 public void setPrevious(Resource previous) { 175 this.prev = (AbstractResource<?>) previous; 176 } 177 178 public String getName() { 179 int e = path.endsWith("/") ? path.length() - 1 : path.length(); 180 int p = path.lastIndexOf('/', e - 1); 181 return p > -1 ? path.substring(p + 1) : path; 182 } 183 184 public String getPath() { 185 return path; 186 } 187 188 public String getTrailingPath() { 189 int len = path.length(); 190 String urlPath = ctx.getUrlPath(); 191 return len < urlPath.length() ? urlPath.substring(len) : "/"; 192 } 193 194 public String getNextSegment() { 195 String p = getTrailingPath(); 196 if (p != null && !"/".equals(p)) { 197 int s = p.startsWith("/") ? 1 : 0; 198 int k = p.indexOf('/', s); 199 if (k == -1) { 200 return s > 0 ? p.substring(s) : p; 201 } else { 202 return p.substring(s, k); 203 } 204 } 205 return null; 206 } 207 208 public String getURL() { 209 return ctx.getServerURL().append(path).toString(); 210 } 211 212 public List<LinkDescriptor> getLinks(String category) { 213 return ctx.getModule().getActiveLinks(this, category); 214 } 215 216 public <A> A getAdapter(Class<A> adapter) { 217 if (adapter == CoreSession.class) { 218 return adapter.cast(ctx.getCoreSession()); 219 } else if (adapter == Principal.class) { 220 return adapter.cast(ctx.getPrincipal()); 221 } 222 if (adapter == WebContext.class) { 223 return adapter.cast(ctx); 224 } 225 if (Resource.class.isAssignableFrom(adapter)) { 226 return adapter.cast(this); 227 } 228 return null; 229 } 230 231 public Resource newObject(String type, Object... args) { 232 return ctx.newObject(type, args); 233 } 234 235 public AdapterResource newAdapter(String type, Object... args) { 236 return ctx.newAdapter(this, type, args); 237 } 238 239 public Template getView(String viewId) { 240 return new View(this, viewId).resolve(); 241 } 242 243 public Template getTemplate(String fileName) { 244 return new Template(this, getModule().getFile(fileName)); 245 } 246 247 public boolean checkGuard(String guard) throws ParseException { 248 return PermissionService.parse(guard).check(this); 249 } 250 251 @Override 252 public String toString() { 253 return type.getName() + " [" + path + "]"; 254 } 255 256}