001/*
002 * (C) Copyright 2006-2008 Nuxeo SAS (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 *     Nuxeo - initial API and implementation
016 *
017 * $Id: DocumentIdCodec.java 22535 2007-07-13 14:57:58Z atchertchian $
018 */
019
020package org.nuxeo.ecm.platform.url.codec;
021
022import java.util.ArrayList;
023import java.util.List;
024import java.util.Map;
025import java.util.regex.Matcher;
026import java.util.regex.Pattern;
027
028import org.apache.commons.logging.Log;
029import org.apache.commons.logging.LogFactory;
030import org.nuxeo.common.utils.StringUtils;
031import org.nuxeo.common.utils.URIUtils;
032import org.nuxeo.ecm.core.api.DocumentLocation;
033import org.nuxeo.ecm.core.api.DocumentRef;
034import org.nuxeo.ecm.core.api.PathRef;
035import org.nuxeo.ecm.core.api.impl.DocumentLocationImpl;
036import org.nuxeo.ecm.platform.url.DocumentViewImpl;
037import org.nuxeo.ecm.platform.url.api.DocumentView;
038import org.nuxeo.ecm.platform.url.service.AbstractDocumentViewCodec;
039
040/**
041 * Codec handling a document repository, path, view and additional request parameters.
042 *
043 * @author Anahide Tchertchian
044 */
045public class DocumentPathCodec extends AbstractDocumentViewCodec {
046
047    // The maximum length of an url for Internet Explorer.
048    public static final int URL_MAX_LENGTH = 2000;
049
050    public static final String PREFIX = "nxpath";
051
052    // nxpath/server/path/to/doc@view_id?requestParams
053    public static final String URL_PATTERN = "/" // slash
054            + "([\\w\\.]+)" // server name (group 1)
055            + "(?:/(.*))?" // path (group 2) (optional)
056            + "@([\\w\\-\\.;=]+)" // view id (group 3)
057            + "/?" // final slash (optional)
058            + "(?:\\?(.*)?)?"; // query (group 4) (optional)
059
060    private static final Log log = LogFactory.getLog(DocumentPathCodec.class);
061
062    public DocumentPathCodec() {
063    }
064
065    public DocumentPathCodec(String prefix) {
066    }
067
068    @Override
069    public String getPrefix() {
070        if (prefix != null) {
071            return prefix;
072        }
073        return PREFIX;
074    }
075
076    @Override
077    public String getUrlFromDocumentView(DocumentView docView) {
078        // Use DocumentIdCodec if the document is a version
079        if ("true".equals(docView.getParameter("version"))) {
080            if (docView.getDocumentLocation().getIdRef() != null) {
081                DocumentIdCodec idCodec = new DocumentIdCodec();
082                return idCodec.getUrlFromDocumentView(docView);
083            }
084        }
085
086        DocumentLocation docLoc = docView.getDocumentLocation();
087        if (docLoc != null) {
088            List<String> items = new ArrayList<String>();
089            items.add(getPrefix());
090            items.add(docLoc.getServerName());
091            PathRef docRef = docLoc.getPathRef();
092
093            if (docRef != null) {
094                // this is a path, get rid of leading slash
095                String path = docRef.toString();
096                if (path.startsWith("/")) {
097                    path = path.substring(1);
098                }
099                if (path.length() > 0) {
100                    items.add(URIUtils.quoteURIPathComponent(path, false));
101                }
102            }
103
104            String uri = StringUtils.join(items, "/");
105            String viewId = docView.getViewId();
106            if (viewId != null) {
107                uri += "@" + viewId;
108            }
109
110            String uriWithParam = URIUtils.addParametersToURIQuery(uri, docView.getParameters());
111
112            // If the URL with the Path codec is to long, it use the URL with
113            // the Id Codec.
114            if (uriWithParam.length() > URL_MAX_LENGTH) {
115
116                // If the DocumentLocation did not contains the document Id, it
117                // use the Path Codec even if the Url is too long for IE.
118                if (null == docView.getDocumentLocation().getIdRef()) {
119                    log.error("The DocumentLocation did not contains the RefId.");
120                    return uriWithParam;
121                }
122
123                DocumentIdCodec idCodec = new DocumentIdCodec();
124                return idCodec.getUrlFromDocumentView(docView);
125
126            } else {
127                return uriWithParam;
128            }
129        }
130        return null;
131    }
132
133    /**
134     * Extracts document location from a Zope-like URL, eg: server/path_or_docId/view_id/tab_id .
135     */
136    @Override
137    public DocumentView getDocumentViewFromUrl(String url) {
138        final Pattern pattern = Pattern.compile(getPrefix() + URL_PATTERN);
139        Matcher m = pattern.matcher(url);
140        if (m.matches()) {
141
142            final String server = m.group(1);
143            String path = m.group(2);
144            if (path != null) {
145                // add leading slash to make it absolute if it's not the root
146                path = "/" + URIUtils.unquoteURIPathComponent(path);
147            }
148            final DocumentRef docRef = path != null ? new PathRef(path) : null;
149            String viewId = m.group(3);
150            int jsessionidIndex = viewId.indexOf(";jsessionid");
151            if (jsessionidIndex != -1) {
152                viewId = viewId.substring(0, jsessionidIndex);
153            }
154
155            // get other parameters
156            String query = m.group(4);
157            Map<String, String> params = URIUtils.getRequestParameters(query);
158
159            final DocumentLocation docLoc = new DocumentLocationImpl(server, docRef);
160
161            return new DocumentViewImpl(docLoc, viewId, params);
162        }
163
164        return null;
165    }
166
167}