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