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