001/*
002 * (C) Copyright 2006-2012 Nuxeo SA (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 *     Bogdan Stefanescu
016 *     Florent Guillaume
017 */
018package org.nuxeo.ecm.webengine;
019
020import org.nuxeo.common.xmap.annotation.XNode;
021import org.nuxeo.common.xmap.annotation.XObject;
022import org.nuxeo.ecm.webengine.util.PathMatcher;
023
024/**
025 * Configure how a given path is handled by the WebEngine filter.
026 * <p>
027 * If <b>autoTx</b> is true (which is the default) then a transaction will be started each time a path matching the
028 * given path specification is requested. (the transaction is started in a filter before the JAX-RS resource is called
029 * and closed after the response is sent to the output stream). If false then no transaction handling is done. The
030 * default is to start a transaction for any path but: [^/]+/skin/.*
031 * <p>
032 * The <b>value</b> attribute is required and must be used to specify the path pattern. The path pattern is either a
033 * prefix or a regular expression. If the <b>regex</b> parameter is true (the default is false) then the value will be
034 * expected to be a regular expression. A prefix denotes a path starting with 'prefix'. Paths are relative to the
035 * webengine servlet (i.e. they correspond to the servlet path info in the JAX-RS servlet) - and always begin with a
036 * '/'.
037 */
038@XObject("path")
039public class PathDescriptor implements Comparable<PathDescriptor> {
040
041    @XNode("@value")
042    protected String value;
043
044    @XNode("@regex")
045    protected boolean regex = false;
046
047    @XNode("@autoTx")
048    protected Boolean autoTx;
049
050    protected PathMatcher matcher;
051
052    public PathDescriptor() {
053    }
054
055    public PathMatcher getMatcher() {
056        return matcher;
057    }
058
059    public String getValue() {
060        return value;
061    }
062
063    public Boolean getAutoTx() {
064        return autoTx;
065    }
066
067    public boolean isAutoTx(boolean defaultValue) {
068        return autoTx == null ? defaultValue : autoTx.booleanValue();
069    }
070
071    public PathMatcher createMatcher() {
072        if (value != null) {
073            if (!value.startsWith("/")) {
074                value = "/" + value;
075            }
076            matcher = regex ? PathMatcher.getRegexMatcher(value) : PathMatcher.getPrefixMatcher(value);
077        } else {
078            throw new IllegalArgumentException("Path value is required");
079        }
080        return matcher;
081    }
082
083    public boolean match(String path) {
084        return matcher.match(path);
085    }
086
087    @Override
088    public boolean equals(Object obj) {
089        if (obj == this) {
090            return true;
091        }
092        if (obj instanceof PathDescriptor) {
093            PathDescriptor pd = ((PathDescriptor) obj);
094            return value != null && value.equals(pd.value) || value == pd.value;
095        }
096        return false;
097    }
098
099    @Override
100    public int hashCode() {
101        return value.hashCode();
102    }
103
104    @Override
105    public String toString() {
106        return value + "; autoTx: " + autoTx;
107    }
108
109    @Override
110    public int compareTo(PathDescriptor o) {
111        if (regex != o.regex) {
112            return regex ? 1 : -1;
113        }
114        int len1 = value.length();
115        int len2 = o.value.length();
116        if (len1 == len2) {
117            return value.compareTo(o.value);
118        }
119        return len2 - len1;
120    }
121
122}