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