/* * (C) Copyright 2006-2008 Nuxeo SA (http://nuxeo.com/) and others. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Contributors: * bstefanescu * * $Id$ */ package org.nuxeo.ecm.webengine.model.impl; import java.net.URI; import java.net.URISyntaxException; import java.security.Principal; import java.text.ParseException; import java.util.List; import java.util.Set; import javax.ws.rs.core.Response; import org.nuxeo.common.utils.URIUtils; import org.nuxeo.ecm.core.api.CoreSession; import org.nuxeo.ecm.webengine.WebException; import org.nuxeo.ecm.webengine.model.AdapterResource; import org.nuxeo.ecm.webengine.model.LinkDescriptor; import org.nuxeo.ecm.webengine.model.Module; import org.nuxeo.ecm.webengine.model.Resource; import org.nuxeo.ecm.webengine.model.ResourceType; import org.nuxeo.ecm.webengine.model.Template; import org.nuxeo.ecm.webengine.model.View; import org.nuxeo.ecm.webengine.model.WebContext; import org.nuxeo.ecm.webengine.model.exceptions.WebSecurityException; import org.nuxeo.ecm.webengine.security.PermissionService; /** * @author <a href="mailto:bs@nuxeo.com">Bogdan Stefanescu</a> */ // DO NOT MODIFY class declaration! Cannot use WebResourceType<?> since groovy // doesn't supports wildcards for now @SuppressWarnings("unchecked") public abstract class AbstractResource<T extends ResourceType> implements Resource { protected WebContext ctx; protected AbstractResource<?> next; protected AbstractResource<?> prev; protected String path; protected T type; @Override public Resource initialize(WebContext ctx, ResourceType type, Object... args) { this.ctx = ctx; this.type = (T) type; path = ctx.getUriInfo().getMatchedURIs().get(0); // quote path component to replace special characters (except slash and // @ chars) path = URIUtils.quoteURIPathComponent(path, false, false); // avoid paths ending in / -> this will mess-up URLs in FTL files. if (path.endsWith("/")) { path = path.substring(0, path.length() - 1); } // resteasy doesn't return correct paths - that should be relative as // is JAX-RS specs on resteasy paths begin with a / StringBuilder buf = new StringBuilder(64).append(ctx.getBasePath()); if (!path.startsWith("/")) { buf.append('/'); } path = buf.append(path).toString(); if (!this.type.getGuard().check(this)) { throw new WebSecurityException("Failed to initialize object: " + path + ". Object is not accessible in the current context", path); } initialize(args); return this; } protected void initialize(Object... args) { // do nothing } @Override public boolean isAdapter() { return type.getClass() == AdapterTypeImpl.class; } @Override public boolean isRoot() { return this == ctx.getRoot(); } @Override public void setRoot(boolean isRoot) { AbstractWebContext ctx = (AbstractWebContext) this.ctx; if (isRoot) { ctx.root = this; } else { if (ctx.root == this) { ctx.root = null; } } } @Override public boolean isInstanceOf(String type) { return this.type.isDerivedFrom(type); } @Override public Response redirect(String uri) { try { if (!uri.contains("://")) { // not an absolute URI if (uri.startsWith("/")) { uri = ctx.getServerURL().append(uri).toString(); } else { uri = ctx.getServerURL().append('/').append(uri).toString(); } } return Response.seeOther(new URI(uri)).build(); } catch (URISyntaxException e) { throw WebException.wrap(e); } } @Override public AdapterResource getActiveAdapter() { return next != null && next.isAdapter() ? (AdapterResource) next : null; } @Override public void dispose() { ctx = null; type = null; path = null; } @Override public Set<String> getFacets() { return type.getFacets(); } @Override public boolean hasFacet(String facet) { return type.hasFacet(facet); } @Override public T getType() { return type; } @Override public WebContext getContext() { return ctx; } @Override public Module getModule() { return ctx.getModule(); } @Override public Resource getNext() { return next; } @Override public void setNext(Resource next) { this.next = (AbstractResource<?>) next; } @Override public Resource getPrevious() { return prev; } @Override public void setPrevious(Resource previous) { this.prev = (AbstractResource<?>) previous; } @Override public String getName() { int e = path.endsWith("/") ? path.length() - 1 : path.length(); int p = path.lastIndexOf('/', e - 1); return p > -1 ? path.substring(p + 1) : path; } @Override public String getPath() { return path; } @Override public String getTrailingPath() { int len = path.length(); String urlPath = ctx.getUrlPath(); return len < urlPath.length() ? urlPath.substring(len) : "/"; } @Override public String getNextSegment() { String p = getTrailingPath(); if (p != null && !"/".equals(p)) { int s = p.startsWith("/") ? 1 : 0; int k = p.indexOf('/', s); if (k == -1) { return s > 0 ? p.substring(s) : p; } else { return p.substring(s, k); } } return null; } @Override public String getURL() { return ctx.getServerURL().append(path).toString(); } @Override public List<LinkDescriptor> getLinks(String category) { return ctx.getModule().getActiveLinks(this, category); } @Override public <A> A getAdapter(Class<A> adapter) { if (adapter == CoreSession.class) { return adapter.cast(ctx.getCoreSession()); } else if (adapter == Principal.class) { return adapter.cast(ctx.getPrincipal()); } if (adapter == WebContext.class) { return adapter.cast(ctx); } if (Resource.class.isAssignableFrom(adapter)) { return adapter.cast(this); } return null; } @Override public Resource newObject(String type, Object... args) { return ctx.newObject(type, args); } @Override public AdapterResource newAdapter(String type, Object... args) { return ctx.newAdapter(this, type, args); } @Override public Template getView(String viewId) { return new View(this, viewId).resolve(); } @Override public Template getTemplate(String fileName) { return new Template(this, getModule().getFile(fileName)); } @Override public boolean checkGuard(String guard) throws ParseException { return PermissionService.parse(guard).check(this); } @Override public String toString() { return type.getName() + " [" + path + "]"; } }