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